#include "flow_module.h"
#include "log_module.h"
#include "alarm_module.h"
#include <rtdevice.h>
#include <rthw.h>

static flow_config_t *flow_config = RT_NULL;
static rt_thread_t flow_thread = RT_NULL;

/* TIM2 handle for input capture */
static TIM_HandleTypeDef htim2;

/* Flow measurement data */
static flow_data_t flow_data[FLOW_CHANNELS];

/* TIM2 input capture callback */
static void flow_tim2_capture_callback(uint8_t channel)
{
    uint32_t capture_value;
    
    if (channel == 1) {
        capture_value = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);
        flow_data[0].pulse_count++;
        __HAL_TIM_SET_COUNTER(&htim2, 0);
    } else if (channel == 2) {
        capture_value = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);
        flow_data[1].pulse_count++;
        __HAL_TIM_SET_COUNTER(&htim2, 0);
    }
}

/* TIM2 IRQ handler */
void TIM2_IRQHandler(void)
{
    if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC1) != RESET) {
        if (__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_CC1) != RESET) {
            __HAL_TIM_CLEAR_IT(&htim2, TIM_IT_CC1);
            flow_tim2_capture_callback(1);
        }
    }
    
    if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC2) != RESET) {
        if (__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_CC2) != RESET) {
            __HAL_TIM_CLEAR_IT(&htim2, TIM_IT_CC2);
            flow_tim2_capture_callback(2);
        }
    }
}

static rt_err_t flow_timer_init(void)
{
    TIM_IC_InitTypeDef sConfigIC;
    
    /* TIM2 clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();
    
    /* Configure TIM2 */
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 7199;  /* 72MHz / 7200 = 10kHz */
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 0xFFFFFFFF;
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    
    if (HAL_TIM_IC_Init(&htim2) != HAL_OK) {
        return RT_ERROR;
    }
    
    /* Configure input capture channel 1 */
    sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
    sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
    sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
    sConfigIC.ICFilter = 0;
    
    if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) {
        return RT_ERROR;
    }
    
    /* Configure input capture channel 2 */
    if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) {
        return RT_ERROR;
    }
    
    /* Start input capture */
    if (HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1) != HAL_OK) {
        return RT_ERROR;
    }
    
    if (HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2) != HAL_OK) {
        return RT_ERROR;
    }
    
    /* Enable TIM2 interrupt */
    HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
    
    return RT_OK;
}

static void flow_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    /* GPIO clock enable */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    /* Configure GPIO pins for TIM2 CH1 and CH2 */
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

static float calculate_flow_rate(uint8_t channel)
{
    uint32_t current_time = rt_tick_get();
    uint32_t time_elapsed = current_time - flow_data[channel].last_calc_time;
    uint32_t pulses = flow_data[channel].pulse_count - flow_data[channel].last_pulse_count;
    
    if (time_elapsed == 0) {
        return 0.0f;
    }
    
    /* Calculate frequency in Hz */
    float frequency = (pulses * 1000.0f) / time_elapsed;
    
    /* Convert to flow rate: flow_rate = frequency / pulse_constant */
    float flow_rate = frequency / flow_config->channels[channel].pulse_constant;
    
    /* Apply calibration factor */
    flow_rate *= flow_config->channels[channel].k_factor;
    
    /* Update total flow */
    float time_hours = time_elapsed / (1000.0f * 3600.0f);
    flow_data[channel].total_flow += (flow_rate * time_hours * 60.0f); /* Convert to liters */
    
    /* Update last values */
    flow_data[channel].last_pulse_count = flow_data[channel].pulse_count;
    flow_data[channel].last_calc_time = current_time;
    
    return flow_rate;
}

static float moving_average_flow_filter(uint8_t channel, float new_flow_rate)
{
    static float flow_buffer[FLOW_CHANNELS][5] = {0};
    static uint8_t flow_index[FLOW_CHANNELS] = {0};
    static float flow_sum[FLOW_CHANNELS] = {0};
    static uint8_t flow_count[FLOW_CHANNELS] = {0};
    
    if (flow_count[channel] < 5) {
        flow_buffer[channel][flow_count[channel]] = new_flow_rate;
        flow_sum[channel] += new_flow_rate;
        flow_count[channel]++;
        return new_flow_rate;
    }
    
    /* Subtract oldest value */
    flow_sum[channel] -= flow_buffer[channel][flow_index[channel]];
    
    /* Add new value */
    flow_buffer[channel][flow_index[channel]] = new_flow_rate;
    flow_sum[channel] += new_flow_rate;
    
    /* Update index */
    flow_index[channel] = (flow_index[channel] + 1) % 5;
    
    return flow_sum[channel] / 5.0f;
}

static void process_flow_message(message_t *msg)
{
    if (msg == RT_NULL) return;
    
    switch (msg->msg_type) {
        case MSG_CONTROL_CMD:
            if (msg->data != RT_NULL) {
                /* Handle flow control commands */
                uint8_t *cmd = (uint8_t *)msg->data;
                if (*cmd == CMD_RESET) {
                    flow_reset_total_flow(0);  /* Reset channel 0 */
                    flow_reset_total_flow(1);  /* Reset channel 1 */
                }
            }
            break;
        default:
            break;
    }
}

rt_err_t flow_module_init(void)
{
    rt_err_t result;
    
    /* Get configuration pointer */
    flow_config = &g_system_config.flow;
    
    /* Initialize GPIO */
    flow_gpio_init();
    
    /* Initialize TIM2 for input capture */
    result = flow_timer_init();
    if (result != RT_OK) {
        LOG_E("Flow timer initialization failed\n");
        return result;
    }
    
    /* Initialize flow data */
    for (int i = 0; i < FLOW_CHANNELS; i++) {
        flow_data[i].pulse_count = 0;
        flow_data[i].last_pulse_count = 0;
        flow_data[i].flow_rate = 0.0f;
        flow_data[i].total_flow = 0.0f;
        flow_data[i].last_calc_time = rt_tick_get();
    }
    
    /* Create flow thread */
    flow_thread = rt_thread_create("flow", 
                                  flow_thread_entry, 
                                  RT_NULL, 
                                  1024, 
                                  13, 
                                  20);
    if (flow_thread == RT_NULL) {
        LOG_E("Failed to create flow thread\n");
        return RT_ERR_MEM;
    }
    
    LOG_I("Flow module initialized successfully\n");
    return RT_OK;
}

void flow_thread_entry(void *parameter)
{
    rt_uint32_t tick;
    float raw_flow_rate, filtered_flow_rate;
    
    while (1) {
        tick = rt_tick_get();
        
        /* Calculate flow rates for all channels */
        for (int i = 0; i < FLOW_CHANNELS; i++) {
            if (!flow_config->channels[i].enabled) {
                continue;
            }
            
            /* Calculate current flow rate */
            raw_flow_rate = calculate_flow_rate(i);
            
            /* Apply filter */
            filtered_flow_rate = moving_average_flow_filter(i, raw_flow_rate);
            
            /* Update configuration */
            flow_config->channels[i].flow_rate = filtered_flow_rate;
            flow_config->channels[i].total_flow = flow_data[i].total_flow;
            flow_config->channels[i].pulse_count = flow_data[i].pulse_count;
        }
        
        /* Send data ready message */
        send_message(MODULE_ALARM, MSG_DATA_UPDATE, RT_NULL, 0);
        send_message(MODULE_MODBUS, MSG_DATA_UPDATE, RT_NULL, 0);
        
        /* Wait for next cycle */
        rt_thread_delay_until(&tick, rt_tick_from_millisecond(flow_config->base.update_interval));
    }
}

float flow_get_flow_rate(uint8_t channel)
{
    if (channel >= FLOW_CHANNELS || flow_config == RT_NULL) {
        return 0.0f;
    }
    
    return flow_config->channels[channel].flow_rate;
}

float flow_get_total_flow(uint8_t channel)
{
    if (channel >= FLOW_CHANNELS || flow_config == RT_NULL) {
        return 0.0f;
    }
    
    return flow_config->channels[channel].total_flow;
}

rt_err_t flow_reset_total_flow(uint8_t channel)
{
    if (channel >= FLOW_CHANNELS) {
        return RT_ERR_PARAM;
    }
    
    flow_data[channel].total_flow = 0.0f;
    flow_config->channels[channel].total_flow = 0.0f;
    
    LOG_I("Flow channel %d total flow reset\n", channel);
    
    return RT_OK;
}

rt_err_t flow_set_calibration(uint8_t channel, float pulse_constant, float k_factor)
{
    if (channel >= FLOW_CHANNELS || flow_config == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    flow_config->channels[channel].pulse_constant = pulse_constant;
    flow_config->channels[channel].k_factor = k_factor;
    
    LOG_I("Flow channel %d calibration updated: pulse_const=%.1f, k_factor=%.3f\n", 
          channel, pulse_constant, k_factor);
    
    return RT_OK;
}

flow_config_t *flow_get_config(void)
{
    return flow_config;
}